package at.donalfonso.ui.pizzeria;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import org.mozartspaces.capi3.CoordinationData;
import org.mozartspaces.capi3.KeyCoordinator;
import org.mozartspaces.capi3.LindaCoordinator;
import org.mozartspaces.core.ContainerReference;
import org.mozartspaces.core.Entry;
import org.mozartspaces.core.MzsCoreException;
import org.mozartspaces.notifications.Notification;
import org.mozartspaces.notifications.NotificationListener;
import org.mozartspaces.notifications.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.donalfonso.model.Bestellung;
import at.donalfonso.model.Gruppe;
import at.donalfonso.model.GruppeStatus;
import at.donalfonso.model.Pizza;
import at.donalfonso.model.Tisch;
import at.donalfonso.model.Tisch.TischStatus;
import at.donalfonso.utility.SpaceUtility;

public class PizzeriaController implements ActionListener, WindowListener, NotificationListener {

	private DefaultListModel<Gruppe> gruppeModel = new DefaultListModel<Gruppe>();
	private DefaultListModel<Tisch> tischModel = new DefaultListModel<Tisch>();
	private DefaultListModel<Bestellung> bestellModel = new DefaultListModel<Bestellung>();
	private DefaultListModel<Integer> platzModel = new DefaultListModel<Integer>();
	private Integer freiePlaetze = 0;
	
	private int filiale;
	private SpaceUtility space;

	private PizzeriaView gui;
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	private String hoechsteBestellID;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int filiale;
		Boolean headless = false;
		
		if (args.length > 1) {
			if (args[1].equals("1"))
				headless = true;
		}
		if (args.length > 0) {
			filiale = Integer.parseInt(args[0]);
		}
		else {
			filiale = 1;
		}
		
		new PizzeriaController(filiale, headless);

	}
	
	public PizzeriaController(int fil, Boolean headless) {
		filiale = fil;
		
		if (! headless) {
			try {
				//"com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
				UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
				//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (UnsupportedLookAndFeelException e) {
				e.printStackTrace();
			}
		
			gui = new PizzeriaView(gruppeModel, tischModel, bestellModel, platzModel);
			gui.addWindowListener(this);
			gui.setTitle("Don Alfonso Filiale " + filiale + ": PizzeriaGUI XVSM");
		}
		
		platzModel.addElement(new Integer(0));
		platzModel.setSize(1);
		
		space = new SpaceUtility(filiale);
		space.initSpace();
		
		try {
			space.getNotificationManager().createNotification(space.getEingangContainer(), this, Operation.WRITE, Operation.TAKE);
			space.getNotificationManager().createNotification(space.getSaalContainer(), this, Operation.WRITE, Operation.TAKE);
			space.getNotificationManager().createNotification(space.getBestellungOffenContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getBestellungZubContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getBestellungFertigContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getZustellungContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getKuecheInputContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getKuecheOutputContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getGruppeSitzenContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getGruppeWillBestellenContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getGruppeHatBestelltContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getGruppeEssenContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getGruppeWillBezahlenContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getGruppeHatBezahltContainer(), this, Operation.WRITE);
			space.getNotificationManager().createNotification(space.getGruppeGegangenContainer(), this, Operation.WRITE);
			
		} catch (MzsCoreException | InterruptedException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}

		try {
			Thread.sleep(1000);
		} catch (InterruptedException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		for (int i=0; i < 10; i++) {
			
			Tisch t = new Tisch();
			
			try {
				//List<CoordinationData> coord =  Arrays.asList(LabelCoordinator.newCoordinationData(t.getStatus().toString()), KeyCoordinator.newCoordinationData(t.getId()+""));
				
				/*
				 * Die Tische werden mit dem Status "Frei" in den Saal-Container gestellt.
				 */
				List<CoordinationData> coord =  Arrays.asList(LindaCoordinator.newCoordinationData(), KeyCoordinator.newCoordinationData(t.getId()));
				space.getCapi().write(new Entry(t, coord), space.getSaalContainer());
				
				//space.getCapi().write(new Entry(t, Arrays.asList(LabelCoordinator.newCoordinationData(t.getStatus().toString()), KeyCoordinator.newCoordinationData(t.getId()+""))), space.getSaalContainer());
				//space.getCapi().write(new Entry(t, LabelCoordinator.newCoordinationData(t.getStatus().toString())), space.getEingangContainer());
			} catch (MzsCoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		erzeugeNeueBestellungen();
		
	}

	public void erzeugeNeueBestellungen() {
		Bestellung b = null;
		
		for (int i = 1; i < 200; i++) {
			b = new Bestellung(filiale);
			try {
				space.getCapi().write(new Entry(b), space.getBestellungNeuContainer());
			} catch (MzsCoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		hoechsteBestellID = b.getBestellungId();
	}

	
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void entryOperationFinished(Notification noti, Operation op,
			List<? extends Serializable> entries) {
		
		logger.debug("processing XVSM notification");

		ContainerReference src = noti.getObservedContainer();
		logger.debug("src getId(): " + src.getId() + " op.name(): " + op.name());
		
		// Zuerst zwischen WRITE und den anderen Operationen unterscheiden
		// bei WRITE ist das eigentliche Objekt noch in Entry() gekapselt
		
		if (op.name() == "WRITE") {
			for (Serializable e: entries) {
				Serializable s = ((Entry) e).getValue();
				if (s instanceof Gruppe) {
					Gruppe g = (Gruppe) s;
					if (g.getStatus() == GruppeStatus.WARTEN)
						gruppeModel.addElement((Gruppe) s);
				}
				
				if (s instanceof Tisch) {
					
					Tisch t = (Tisch) s;
										
					if (t.getStatus().equals(TischStatus.FREI))
						freiePlaetze += t.getPlaetze();
					if (t.getStatus().equals(TischStatus.BESETZT))
						freiePlaetze -= t.getPlaetze();
					platzModel.set(0, freiePlaetze);
					
					int index = tischModel.indexOf(t);
					if (index < 0)
						tischModel.addElement(t);
					else
						tischModel.set(index, t);
				}
				/*
				if (src.getId().equals(space.getSaalContainer().getId()) && s instanceof Tisch) {
						tischModel.addElement((Tisch) s);
				}
				*/
				
				if (s instanceof Bestellung) {
					Bestellung b = (Bestellung) s;
					logger.debug("WRITE best:" + b);
					int index = bestellModel.indexOf(b);
					if (index < 0)
						bestellModel.addElement(b);
					else
						bestellModel.set(index, b);
					
					// Bestellungen werden wegen eindeutigen IDs hier erzeugt
					// Vorrat erschöpft, neue erzeugen
					if (b.getBestellungId().equals(hoechsteBestellID))
						erzeugeNeueBestellungen();
				}
				
				if (s instanceof Pizza) {
					Pizza p = (Pizza) s;
					for (int i=0; i < bestellModel.size(); i++) {
						Bestellung b = bestellModel.get(i);
						if (b.getBestellungId().equals(p.getBestellnummer()))
							bestellModel.set(i, b);
					}
				}
			}
		}
		
		if (op.name() == "TAKE") {
			for (Serializable s: entries) {
				if (s instanceof Gruppe) {
					gruppeModel.removeElement((Gruppe) s);
				}
/*
				if (s instanceof Tisch) {
					Tisch t = (Tisch) s;
					freiePlaetze -= t.getPlaetze();
					platzModel.set(0, freiePlaetze);
					tischModel.removeElement(t);
				}
				if (s instanceof LieferBestellung && 
						src.getId().equals(space.getBestellungOffenContainer().getId())) {
					LieferBestellung b = (LieferBestellung) s;
					// logger.debug("TAKE best:" + b);
					bestellModel.removeElement(b);
				}  
*/
			}
		}

//		gui.repaint();
//		gui.validate();
	}

	@Override
	public void windowActivated(WindowEvent arg0) {
		
	}

	@Override
	public void windowClosed(WindowEvent arg0) {

	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		logger.info("Shutdown.");
//		shutdownSpace();
		space.getNotificationManager().shutdown();
		space.shutdown();
		System.exit(0);
	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {
		
	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {
		
	}

	@Override
	public void windowIconified(WindowEvent arg0) {
	
	}

	@Override
	public void windowOpened(WindowEvent arg0) {
		
	}
	
}
